// Monaco Editor 编辑区

<template>
  <div class="editor" :style="{ width }">
    <!-- 仅依靠 el-tabs 提供顶部标签页功能 -->
    <el-tabs
      v-if="openFileList.length"
      v-model="currentFile!.id"
      type="border-card"
      closable
      @tab-click="switchFile"
      @tab-remove="removeFile"
    >
      <el-tab-pane
        v-for="file in openFileList"
        :key="file.id"
        :name="file.id"
        :label="file.label"
      >
        <template #label>
          <img :src="Utils.getFileIcon(file.label)" alt="" />
          <span :data-fileid="file.id">{{ file.label }}</span>
        </template>
      </el-tab-pane>
    </el-tabs>

    <!-- 这里可不能仅仅是 MonacoEditor，还应该支持 图片、视频、markdown 等文件类型的预览 -->
    <div class="editor-content" ref="EditorContentRef">
      <!-- 代码编辑 type=File -->
      <MonacoEditorVue
        ref="editorRef"
        v-if="currentFile?.type === 'File'"
        @windowResize="windowResize"
      />

      <!-- 图片预览 type=Image -->
      <img
        v-else-if="currentFile?.type === 'Image'"
        :src="currentFileContent"
      />

      <!-- Empty File -->
      <div class="editor-empty-file" v-else>
        <img src="../../assets/logo.svg" alt="" />
      </div>
    </div>

    <!-- 需要在 Editor 中拖拽调整大小 -->
    <div class="unicode-drag-bar" @mousedown="dragBarHandle"></div>
  </div>
</template>

<script setup lang="ts">
import { Utils } from "../../utils";
import {
  nextTick,
  onBeforeUnmount,
  onMounted,
  reactive,
  ref,
  watch,
} from "vue";
import { TabPaneName, TabsPaneContext } from "element-plus";
import { IFileTreeItem } from "../../interface/FileTree";
import MonacoEditorVue from "./components/MonacoEditor.vue";
import WebContainerAPI from "../../class/WebContainerAPI";
import { mousedownHandler } from "../../utils/unicode-drag-bar";
import { ISearchToEditorResult } from "../../interface";
import { useEditorStore } from "../../pinia/useEditorStore";

const editorStore = useEditorStore();

const EditorContentRef = ref(null);
// 定义宽度
const width = ref("50%");

// Monaco Editor 编辑器实例
const editorRef = ref(<InstanceType<typeof MonacoEditorVue> | null>null);

// 为了实现多 tab 页，需要定义当前打开的文件列表
const openFileList = reactive(<IFileTreeItem[]>[]);
const currentFile = ref(<IFileTreeItem | null>{});

/**
 * 定义当前文件内容
 *  File 类型直接通过 Monaco Editor 读取
 *  Image 类型，通过 web Container 读取后，生成 Bolb 路径
 */
const currentFileContent = ref(<string | undefined>"");

/**
 * 外部交互的重要窗口 - 通过监听 fileTree 点击的文件，实现打开文件
 */
watch(() => editorStore.currentFile, watchOpenFile, { deep: true });
async function watchOpenFile(item: IFileTreeItem | null) {
  if (!item) return;

  // 判断是否已经存在，如果存在，直接跳转到该文件 tabs 并重新渲染内容
  const file = openFileList.find((i) => i.id === item.id);

  if (file) {
    currentFile.value = file;
    // 还需要处理 Monaco Editor 内容
    editorRef.value?.setEditorContent({ id: file.id });
    return;
  }

  // 先处理页面逻辑 - 添加到 openFileList 激活 tab
  openFileList.push(item);
  currentFile.value = item;

  // 再处理 Monaco Editor 内容
  await nextTick();
  if (item.type === "File") {
    // 读取文件内容
    const content = await WebContainerAPI.readFileContent(item.id);
    const suffix = Utils.getFileSuffix(item.label);
    const id = item.id;
    // 设置编辑器的内容
    editorRef.value?.setEditorContent({ content, suffix, id });
  } else if (item.type === "Image") {
    // 如果是 Image 类型，则通过 web Container 读取后，生成 Bolb 路径
    // const blobUrl = await fileTreeStore.readFileContent;
  }
}

/**
 * 外部交互的 重要窗口 - 通过监听 search 结果用户点击的 findMatchs 实现打开文件
 */
watch(() => editorStore.currentSearch, searchResult, { deep: true });
async function searchResult(item: ISearchToEditorResult | null) {
  if (!item) return;

  // 判断是否已经存在，如果存在，直接跳转到该文件 tabs 并重新渲染内容
  const { filepath, result } = item;
  const file = openFileList.find((i) => i.id === filepath);

  if (file) {
    currentFile.value = file;
    // 还需要处理 Monaco Editor 内容
    editorRef.value?.setEditorContent({ id: file.id });
  } else {
    // 如果不存在，则添加到 openFileList 激活 tab
    // 解析文件名 /src/index.js ===> index.js
    const label = Utils.getFileName(filepath);
    const newFile = <IFileTreeItem>{ id: filepath, label, type: "File" };
    openFileList.push(newFile);
    currentFile.value = newFile;

    await nextTick();
    // 然后处理 Monaco Editor 内容
    // 读取文件内容
    const content = await WebContainerAPI.readFileContent(filepath);
    const suffix = Utils.getFileSuffix(label);
    // 设置编辑器的内容
    editorRef.value?.setEditorContent({ content, suffix, id: filepath });
  }

  // 接着 跳转到 findMatchs range 的位置,并居中
  await nextTick();

  editorRef.value?.revealRangeInCenter(result.range);

  // 并且需要选中 keyword
  editorRef.value?.setSelection(result.range);
}

/**
 * 切换文件 tabs click handle
 */
function switchFile(tab: TabsPaneContext) {
  const id = <string>tab.props.name;
  currentFile.value = openFileList.find((item) => item.id === id)!;

  // 还需要处理 Monaco Editor 内容
  editorRef.value?.setEditorContent({ id });

  // 需要反馈当前激活的文件
  // fileTreeStore.setSwitchFile(id);
}

/**
 * mouseMiddleClick 鼠标中间键 点击事件
 */
function mouseMiddleClick(e: MouseEvent) {
  const target = <HTMLElement>e.target;
  if (e.button !== 1 || !target.classList.contains("el-tabs__item")) return;
  // 阻止默认事件
  e.preventDefault();
  //  获取ID
  const fileid = target.querySelector("span")?.dataset.fileid;
  if (!fileid) return;

  removeFile(fileid);
}

/**
 * 删除文件操作
 * removeFile
 */
function removeFile(name: TabPaneName) {
  // 获取文件索引
  const index = openFileList.findIndex((item) => item.id === name);

  // 先跳转到该文件 - 实现类似 vscode 关闭前，先判断文件是否保存的功能
  editorRef.value?.setEditorContent({ id: name as string });

  openFileList.splice(index, 1);

  // 如果删除后，已经没有文件了，则清空 currentFile
  if (!openFileList.length) return (currentFile.value = null);

  // 如果删除的是当前文件，则默认切换到第一个文件
  if (currentFile.value?.id === name) {
    currentFile.value = openFileList[0];
  }

  // 同时 删除 viewState
  editorRef.value?.removeViewState(name as string);

  // 下一个文件的 id
  editorRef.value?.setEditorContent({ id: currentFile.value!.id! });
}

function dragBarHandle(e: MouseEvent) {
  const temp = width.value; // calc(50% - 10px)  会自动合并计算 得到 ==> calc(50% - 20px)

  mousedownHandler(e, "lr", (dx: number) => {
    width.value = `calc(${temp} + ${dx}px)`;
    windowResize();
  });
}

function windowResize() {
  const style = getComputedStyle(EditorContentRef.value!);
  editorRef.value?.resize({
    width: Number(style.width.replace("px", "")),
    height: Number(style.height.replace("px", "")),
  });
}

onMounted(() => {
  window.addEventListener("mousedown", mouseMiddleClick);
});
onBeforeUnmount(() => {
  window.removeEventListener("mousedown", mouseMiddleClick);
});
</script>

<style lang="css" scoped>
.editor {
  position: relative;
  height: 100%;
}
.editor .unicode-drag-bar {
  position: absolute;
  top: 0;
  right: 0;
  width: var(--base);
  height: 100%;
  cursor: ew-resize;
  transform: translateX(50%);
}
.editor-content {
  height: calc(100% - 45px);
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.editor-empty-file {
  user-select: none;
  opacity: 0.4;
}
:deep().el-tabs__header {
  margin-bottom: 0;
}
:deep().el-tabs__item {
  user-select: none;
  padding: 0 10px !important;
}
:deep().el-tabs__item img {
  height: 26px;
  pointer-events: none;
}
:deep().el-tabs__item span {
  pointer-events: none;
}

:deep().el-tabs__content {
  display: none;
}
:deep().el-tabs__header .el-tabs__nav {
  border-radius: 0;
  border-top-width: 0;
}
/* :deep().minimap-decorations-layer {
  background-color: var(--t-main-background-color);
}
:deep().decorationsOverviewRuler {
  background-color: var(--t-main-background-color);
}
:deep().monaco-editor {
  --vscode-editor-background: var(--t-main-background-color);
  --vscode-editorGutter-background: var(--t-main-background-color);
  --vscode-scrollbarSlider-background: var(--t-main-background-color);
} */
</style>
